<?php
/**
 * This file contains the class ResetPasswordModel which provides
 * most of the code requirements for the Member page
 *
 * @copyright  2009 A Memory Tree
 * @license    A Memory Tree License
 * @version    $Id:$
 * @link       http://my-trac.assembla.com/amemorytree/ticket/??
 * @since      File available since Release 0.1
 */
/**
 * This class provides the code for the reset password page
 *
 * @copyright  2009 A Memory Tree
 * @license    A Memory Tree License
 * @version    Release: @package_version@
 * @link       http://my-trac.assembla.com/amemorytree/ticket/??
 * @since      Class available since Release 0.1
 */
class ResetPasswordModel
{
    /**
     * Access to the database methods
     *
     * @var MemberDB
     */
    private $_db;
    /**
     * Access to the View methods
     *
     * @var ResetPasswordView
     */
    private $_view;
    /**
     * Access to the Email methods
     *
     * @var EmailModel
     */
    private $_email;
    /**
     * Access to the Authorisation methods
     *
     * @var AuthorisationModel
     */
    private $_auth;
    /**
     * Create a new instance of this class
     *
     * @return void
     * @param MemberDB $db
     * @param ResetPasswordView $view
     * @param AuthorisationModel $auth
     * @param EmailModel $email
     */
    public function __construct($db, $view, $auth, $email)
    {
        $this->_db = $db;
        $this->_view = $view;
        $this->_email = $email;
        $this->_auth = $auth;
    }
    /**
     * Check if the password was used to create the passCode
     *
     * @return bool
     * @param string $password
     * @param string $passCode
     */
    function isValidPassword($password, $passCode)
    {
        $isValid = crypt($password, $passCode) === $passCode;
        return $isValid;
    }
    /**
     * Check if the password is valid for the given user id
     *
     * @return bool
     * @param int $userId
     * @param string $password
     */
    function checkPassword($userId, $password)
    {
        $db = $this->_db;
        $passCode = $db->getPassword($userId);
        $isValid = $this->isValidPassword($password, $passCode);
        return $isValid;
    }
    /**
     * Login the user
     *
     * @return string
     * @param string $username
     * @param string $password
     */
    function loginUser($username, $password)
    {
        $db = $this->_db;
        $view = $this->_view;
        $message = '';
        $userId = $db->getUserId($username);
        $validPassword = $this->checkPassword($userId, $password);
        if ($validPassword) {
            $_SESSION['user'] = $userId;
        } else {
            $message .= $view->text('loginFailed');
        }
        return $message;
    }
    /**
     * Return an encrypted form of a string
     *
     * @return string
     * @param string $str
     */
    function encrypt($str)
    {
        return crypt($str, 'm3m0ry7r33');
    }
    /**
     * Check if the authorisation is correct, and if it is, save the password to the user account
     *
     * @return bool
     * @param string $username
     * @param string $password
     * @param string $authCode
     */
    function setPassword($username, $password, $authCode)
    {
        $db = $this->_db;
        $success = FALSE;
        $userId = $db->getUserId($username);
        if ($authCode === $db->getAuthCode($userId)) {
            $success = $db->setPassword($userId, $this->encrypt($password));
            if ($success) {
                $success = $db->removeAuthCode($userId);
            }
        }
        return $success;
    }
    /**
     * Change the password of a users account
     *
     * This change occurs only if the old password is correctly given, and
     * the new password correctly matches the duplicate confirmation password
     *
     * @return string
     * @param int $userId
     * @param array[string]string $passwords
     */
    function processNewPassword($userId, $passwords)
    {
        $db = $this->_db;
        $old = $passwords['old'];
        $encrypted = $passwords['encrypted'];
        $newPassword = $passwords['new'];
        $confirmPassword = $passwords['confirm'];
        $result = 'incorrect';
        if ($this->isValidPassword($old, $encrypted)) {
            if ($newPassword === $confirmPassword) {
                $db->setPassword($userId, $this->encrypt($newPassword));
                $result = 'changed';
            } else {
                $result = 'unchanged';
            }
        }
        return $result;
    }
    /**
     * Change a users password
     *
     * @return string
     * @param array[string]mixed &$session
     * @param string $oldPass
     * @param string $newPass
     * @param string $confirmPass
     */
    function changePassword(&$session, $oldPass, $newPass, $confirmPass)
    {
        $db = $this->_db;
        $userId = intval($session['user']);
        $passwordResult = $this->processNewPassword($userId, array(
            'encrypted' => $db->getPassword($userId),
            'old' => $oldPass,
            'new' => $newPass,
            'confirm' => $confirmPass
            )
        );
        return $passwordResult;
    }
    /**
     * Send an email to reset the users password
     *
     * @return string
     * @param string $name
     */
    function resetPassword($name)
    {
        $db = $this->_db;
        $view = $this->_view;
        $auth = $this->_auth;
        $email = $this->_email;
        $text = '';
        $userId = $db->getUserId($name);
        if (empty($userId)) {
            $text = $view->badUsername();
            $text .= $view->resetPasswordPage();
        } else {
            $username = $db->getUsername($userId);
            $emailAddress = $db->getEmail($userId);
            $authCode = $auth->createAuthCode($userId);
            $email->setToEmail($emailAddress);
            $email->setSubject('A Memory Tree Password Change Email');
            $email->setMessage($view->resetEmail($userId, $username, $authCode));
            $success = $email->send();
            $text .= $view->emailSent($emailAddress);
        }
        return $text;
    }
    /**
    * Redirect a user to a different page
    *
    * @return string
    * @param string $name
    * @param string $page
    * @param string $querystring
    */
    function redirect($name, $page, $querystring = '')
    {
        $view = $this->_view;
        if (!empty($querystring)) {
            $querystring = '?' . $querystring;
        }
        return $view->redirect($name, $page.$querystring);
    }
    /**
    * Redirect a user to the set password page
    *
    * @return string
    * @param int $userId
    * @param string $auth
    */
    function redirectSetPassword($userId, $auth)
    {
        if (!empty($userId) && !empty($auth)) {
            $page = $_SERVER['PHP_SELF'];
            $querystring = 'userid=' . $userId;
            $querystring .= '&auth=' . $auth;
            return $this->redirect('Set Password', $page, $querystring);
        } else {
            return '';
        }
    }
    /**
    * Redirect a user to a specified page
    *
    * A return page of alerts.php will generate a name of Alerts
    * @return string
    * @param int $userId
    */
    function redirectPage($userId, $returnPage='')
    {
        $view = $this->_view;
        $querystring = '';
        if (!empty($userId)) {
            $pageName = '';
            if (!empty($returnPage)) {
                $pattern = '/([^.]*).*/'; // everything before the fullstop
                $replacement = '$1';
                $pageName = preg_replace($pattern, $replacement, $returnPage);
                $pageName = ucfirst($pageName);
            } else {
                $pageName = 'Login';
                $returnPage = 'member.php';
                $querystring = 'userid=' . $userId;
            }
            return $this->redirect($pageName, $returnPage, $querystring);
        } else {
            return '';
        }
    }
    /**
    * Redirect a user to the member page
    *
    * @return string
    * @param int $userId
    */
    function redirectLogin($userId)
    {
        return $this->redirectPage($userId);
    }
    /**
    * Process a password to be confirmed
    *
    * @return string
    * @param string $username
    * @param string $resetPassword
    * @param string $confirmPassword
    * @param string $authCode
    */
    function confirmPassword($username, $resetPassword, $confirmPassword, $authCode, $returnPage)
    {
        $db = $this->_db;
        $view = $this->_view;
        
        $text = '';
        $userId = $db->getUserId($username);
        if ($resetPassword === $confirmPassword) {
            if (!empty($authCode)) {
                if ($this->setPassword($username, $resetPassword, $authCode)) {
                    $this->loginUser($username, $resetPassword);
                    $text .= $view->text('setSuccess');
                } else {
                    $text .= $view->text('setFailure');
                }
                $text .= $this->redirectPage($userId, $returnPage);
            }
        } else {
            $text = $view->text('badPassword');
            $text .= $this->redirectSetPassword($userId, $authCode);
        }
        return $text;
    }
    /**
     * Show the user login page
     *
     * @return string
     * @param int $userId
     * @param string $authCode
     */
    function userLogin($userId, $authCode, $returnPage)
    {
        $db = $this->_db;
        $view = $this->_view;
        $auth = $this->_auth;
        $text = '';
        $heading = '<h3 style="padding:2px;">User Login</h3>';
        $username = $db->getUsername($userId);
        $hours = 2;
        if ($auth->validate($userId, $authCode, $hours)) {
            $text .= $view->authenticationSuccess();
            $text .= $view->loginForm($username, $authCode, $returnPage);
        } else {
            $text .= $view->authenticationFailure();
        }
        return $text;
    }
}
?>